/*=============================================================================

  IOEMUL DIGITAL IO HAL MODULE

  FILE: DioHal_ioEmul.c
  
  DESCRIPTION

    ioEmul Digital IO HAL Module

  EXTERNALIZED FUNCTIONS


   Copyright (c) DaeSung Engineering Inc. All rights reserved.

=============================================================================*/
/*=============================================================================

  EDIT HISTORY

  ---------  -------  -------------------------------------------------------
    when       who       what, where, why
  ---------  -------  -------------------------------------------------------
   07/17/04   nso4th    Initial version

=============================================================================*/

/*=============================================================================
  HEADER INCLUSION
=============================================================================*/
#include <OBase.h>
#include <mxBase/dioDev.h>
#include <devSP/dev_mem.h>
#include "ioHal_emul.h"
#include <stdlib.h>

/*=============================================================================
  CONSTANT DEFINITIONS
=============================================================================*/
#define IO_MAX_CHANNEL		(128)
#define IO_MAX_BLOCK		(4) // for 128 IO

#define IO_SYNC_WAITTIME	(1000)

/*=============================================================================
  MACRO DEFINITION
=============================================================================*/

/*=============================================================================
  STRUCTURES
=============================================================================*/
typedef struct
{
	boolean		bInit;
	dword		dwID;
	
	dword		dwInNum;
	dword		dwOutNum;
	
	dword		dwInVal[IO_MAX_BLOCK];
	dword		dwOutVal[IO_MAX_BLOCK];

	dword		dwInBlockNum;
	dword		dwOutBlockNum;

	// Sync. object
	CRITICAL_SECTION	cs;
	
	mcxt		pObj;
} CustIo_s;

#define devENTER(tbl) { \
	EnterCriticalSection(&(tbl->cs)); \
 }

#define devLEAVE(tbl) { \
	LeaveCriticalSection(&(tbl->cs)); \
 }

/*=============================================================================
  LOCALIZED FUCNTIONS
=============================================================================*/
static DioHal_s		*gpioEmul = NULL;

// HAL Interface
static dword ioEmul_Execute(mcxt pDev, dword dwCmd, dword wParam, dword lParam);
static dword ioEmul_SetParam(mcxt pDev, dword dwType, dword wParam, dword lParam);
static dword ioEmul_GetParam(mcxt pDev, dword dwType, dword wParam, dword lParam);

// Allocation and Release
static mcxt ioEmul_Alloc(mcxt pObj, dword dwID);
static dword ioEmul_Free(CustIo_s *pDev);
static dword ioEmul_Init(CustIo_s *pDev);
static dword ioEmul_Close(CustIo_s *pDev);

// IO's
dword ioEmul_Output(CustIo_s *pDev, dword dwBlock, dword dwOut);
dword ioEmul_OutputBit(CustIo_s *pDev, dword dwChan, boolean bOn);
dword ioEmul_OutputGet(CustIo_s *pDev, dword dwBlock, dword *pOut);
dword ioEmul_OutputBitGet(CustIo_s *pDev, dword dwChan, boolean *pOn);
dword ioEmul_Input(CustIo_s *pDev, dword dwBlock, dword* pIn);
dword ioEmul_InputBit(CustIo_s *pDev, dword dwChan, boolean *pOn);

dword ioEmul_InputSet(CustIo_s *pDev, dword dwBlock, dword dwIn);
dword ioEmul_InputBitSet(CustIo_s *pDev, dword dwChan, boolean bOn);

// SYNC Task
//dword __stdcall ioEmulSync_Task(void *pSync);

/*=============================================================================
  EXTERNALIZED FUNCION DEFINITION
=============================================================================*/
boolean DioHal_Emul_Register(void)
{
	DioHal_s		*pHal = gpioEmul;

	if(pHal == NULL)
	{
		gpioEmul = memCalloc(sizeof(*gpioEmul));
		pHal = gpioEmul;
	}

	pHal->dwDevID = DIODEV_EMULATOR;
	pHal->pfnTaskCb = NULL;

	pHal->SetParamF = ioEmul_SetParam;
	pHal->GetParamF = ioEmul_GetParam;
	pHal->ExecuteF = ioEmul_Execute;

	return	DioDev_HalRegister(pHal);
}

boolean DioHal_Emul_Deregister(void)
{
	DioHal_s		*pHal = gpioEmul;

	if(pHal)
	{
		DioDev_HalDeregister(pHal);
		memFree(pHal);
		pHal = NULL;
		gpioEmul = NULL;

		return	TRUE;
	}
	
	return	FALSE;
}

/*=============================================================================
  HAL INTERFACING FUNCTIONS
=============================================================================*/
dword ioEmul_SetParam(mcxt pDev, dword dwType, dword wParam, dword lParam)
{
	CustIo_s	*pIO = (CustIo_s*)pDev;

	switch(dwType)
	{
	case DIO_OUT_CHAN_NUM_P:
	{
		if(wParam > IO_MAX_CHANNEL)
			return	FALSE;

		pIO->dwOutNum = wParam;

		if((pIO->dwOutNum%32) == 0)
		{
			pIO->dwOutBlockNum = pIO->dwOutNum / 32;
		}
		else
		{
			pIO->dwOutBlockNum = (dword)(pIO->dwOutNum / 32) + 1;
		}
		return	TRUE;
	}
	case DIO_IN_CHAN_NUM_P:
	{
		if(wParam > IO_MAX_CHANNEL)
			return	FALSE;

		pIO->dwInNum = wParam;
		if((pIO->dwInNum%32) == 0)
		{
			pIO->dwInBlockNum = pIO->dwInNum / 32;
		}
		else
		{
			pIO->dwInBlockNum = (dword)(pIO->dwInNum / 32) + 1;
		}
		return	TRUE;
	}
	
	// IOEMUL COMMAND
	case DIO_HAL_BASE_P:
	default:
		break;
	}

	return	FALSE;
}

dword ioEmul_GetParam(mcxt pDev, dword dwType, dword wParam, dword lParam)
{
	CustIo_s	*pIO = (CustIo_s*)pDev;

	switch(dwType)
	{
	case DIO_OUT_CHAN_NUM_P:
	{
		if(wParam)
		{
			(dword)(*((dword*)wParam)) = pIO->dwOutNum;
		}
		return	pIO->dwOutNum;
	}
	case DIO_IN_CHAN_NUM_P:
	{
		if(wParam)
		{
			(dword)(*((dword*)wParam)) = pIO->dwInNum;
		}
		return	pIO->dwInNum;
	}
	// IOEMUL COMMAND
	case DIO_HAL_BASE_P:
	default:
		break;
	}
	return	FALSE;
}

dword ioEmul_Execute(mcxt pDev, dword dwCmd, dword wParam, dword lParam)
{
	CustIo_s	*pIO = (CustIo_s*)pDev;

	switch(dwCmd)
	{
	//--------------------------------------------
	// ALLOCATION AND RELEASE
	//--------------------------------------------
	case DIO_ALLOC_C:
		return	(dword)ioEmul_Alloc((mcxt)wParam, lParam);

	case DIO_FREE_C:
		return	ioEmul_Free(pIO);

	case DIO_INIT_C:
		return	ioEmul_Init(pIO);

	case DIO_CLOSE_C:
		return	ioEmul_Close(pIO);

	//--------------------------------------------
	// IO
	//--------------------------------------------
	case DIO_OUTPUT_C: // wParam[in] = Block address, lParam[in] = 32 Bit
		return	ioEmul_Output(pIO, wParam, lParam);
				
	case DIO_OUTBIT_C: // wParam[in] = Channel, lParam[in] = TRUE/FALSE
		return	ioEmul_OutputBit(pIO, wParam, (boolean)lParam);

	case DIO_OUTPUT_GET_C: // wParam[in] = Block address, lParam[out] = 32 Bit Pointer
		return	ioEmul_OutputGet(pIO, wParam, (dword*)lParam);

	case DIO_OUTBIT_GET_C: // wParam[in] = Channel, lParam[out] = TRUE/FALSE (Pointer)
		return ioEmul_OutputBitGet(pIO, wParam, (boolean*)lParam);

	case DIO_INPUT_C: // wParam[in] = Block address, lParam[out] = 32 Bit pointer
		return ioEmul_Input(pIO, wParam, (dword*)lParam);

	case DIO_INPUTBIT_C: // wParam[in] = Channel, lParam[out] = TRUE/FALSE (Pointer)
		return	ioEmul_InputBit(pIO, wParam, (boolean*)lParam);
	
	//--------------------------------------------
	// CUST COMMAND
	//--------------------------------------------
	case DIO_HAL_BASE_C:
		break;

	case DIO_EMUL_INPUT_SET_C:
		return	ioEmul_InputSet(pIO, wParam, lParam);
		
	case DIO_EMUL_INPUTBIT_SET_C:
		return	ioEmul_InputBitSet(pIO, wParam, (boolean)lParam);
		
	default:
		break;
	}
	
	return	FALSE;
}

/*=============================================================================
  HARDWARE INTERFACING FUNCTIONS
=============================================================================*/
mcxt ioEmul_Alloc(mcxt pObj, dword dwID)
{
	CustIo_s		*pDev;

	pDev = memCalloc(sizeof(*pDev));
	pDev->pObj = pObj;
	pDev->dwID = dwID;

	return	pDev;
}

dword ioEmul_Free(CustIo_s *pDev)
{
	if(pDev)
	{
		if(pDev->bInit)
		{
			ioEmul_Close(pDev);
		}
		
		memFree(pDev);
		return	TRUE;
	}

	return	FALSE;
}

dword ioEmul_Init(CustIo_s *pDev)
{
	if(pDev->bInit)
		return	FALSE;

	pDev->dwInNum = 32;
	pDev->dwOutNum = 32;

	pDev->dwInBlockNum = 1;
	pDev->dwOutBlockNum = 1;

	memZeros(&pDev->dwInVal[0], sizeof(pDev->dwInVal));
	memZeros(&pDev->dwOutVal[0], sizeof(pDev->dwOutVal));

	InitializeCriticalSectionAndSpinCount(&pDev->cs, 8000);
	
	pDev->bInit = TRUE;

	return	TRUE;
}

dword ioEmul_Close(CustIo_s *pDev)
{
	if(!pDev->bInit)
		return	FALSE;


	devLEAVE(pDev);
	DeleteCriticalSection(&pDev->cs);
	
	pDev->bInit = FALSE;

	return	TRUE;
}


//---------------------------------------------------------
// IO's
//---------------------------------------------------------
dword ioEmul_Output(CustIo_s *pDev, dword dwBlock, dword dwOut)
{
	if(pDev->bInit == FALSE)
		return	FALSE;
	
	if(pDev->dwOutNum == 0)
		return	FALSE;

	if(!RANGE_IN(dwBlock, 0, (pDev->dwOutBlockNum-1)))
		return	FALSE;

devENTER(pDev);
	pDev->dwOutVal[dwBlock] = dwOut;
devLEAVE(pDev);

	return	TRUE;
}

dword ioEmul_OutputBit(CustIo_s *pDev, dword dwChan, boolean bOn)
{
	dword	blkID, blkChan;
	dword	dwMask;

	if(pDev->bInit == FALSE)
		return	FALSE;
	
	if(pDev->dwOutNum == 0)
		return	FALSE;
	blkID = dwChan/32;
	blkChan = dwChan%32;

	if(!RANGE_IN(blkID, 0, (pDev->dwOutBlockNum-1)))
		return	FALSE;

	if(!RANGE_IN(dwChan, 0, (pDev->dwOutNum-1)))
		return	FALSE;

devENTER(pDev);
	if(bOn)
	{
		dwMask = (0x01 << blkChan);
		pDev->dwOutVal[blkID] |= dwMask;
	}
	else
	{
		dwMask = (0x01 << blkChan);
		pDev->dwOutVal[blkID] &= (~dwMask);
	}
devLEAVE(pDev);

	return TRUE;
}

dword ioEmul_OutputGet(CustIo_s *pDev, dword dwBlock, dword *pOut)
{
	if(pDev->bInit == FALSE)
		return	FALSE;

	if(pDev->dwOutNum == 0)
		return	FALSE;

	if(!RANGE_IN(dwBlock, 0, (pDev->dwOutBlockNum-1)))
		return	FALSE;

devENTER(pDev);
	*pOut = pDev->dwOutVal[dwBlock];
devLEAVE(pDev);

	return	TRUE;
}

dword ioEmul_OutputBitGet(CustIo_s *pDev, dword dwChan, boolean *pOn)
{
	dword	blkID, blkChan;

	if(pDev->bInit == FALSE)
		return	FALSE;
	
	if(pDev->dwOutNum == 0)
		return	FALSE;

	blkID = dwChan/32;
	blkChan = dwChan%32;

	if(!RANGE_IN(blkID, 0, (pDev->dwOutBlockNum-1)))
		return	FALSE;

	if(!RANGE_IN(dwChan, 0, (pDev->dwOutNum-1)))
		return	FALSE;

devENTER(pDev);
	*pOn = ISON(pDev->dwOutVal[blkID], blkChan);
devLEAVE(pDev);

	return	TRUE;
}

dword ioEmul_Input(CustIo_s *pDev, dword dwBlock, dword* pIn)
{
	if(pDev->bInit == FALSE)
		return	FALSE;

	if(pDev->dwInNum == 0)
		return	FALSE;

	if(!RANGE_IN(dwBlock, 0, (pDev->dwInBlockNum-1)))
		return	FALSE;

devENTER(pDev);
	*pIn = pDev->dwInVal[dwBlock];
devLEAVE(pDev);

	return	TRUE;
}

dword ioEmul_InputBit(CustIo_s *pDev, dword dwChan, boolean *pOn)
{
	dword	blkID, blkChan;

	blkID = dwChan/32;
	blkChan = dwChan%32;

	if(pDev->bInit == FALSE)
		return	FALSE;
	
	if(pDev->dwInNum == 0)
		return	FALSE;

	if(!RANGE_IN(blkID, 0, (pDev->dwInBlockNum-1)))
		return	FALSE;

	if(!RANGE_IN(dwChan, 0, (pDev->dwInNum-1)))
		return	FALSE;

devENTER(pDev);
	*pOn = ISON(pDev->dwInVal[blkID], blkChan);
devLEAVE(pDev);

	return	TRUE;
}

dword ioEmul_InputSet(CustIo_s *pDev, dword dwBlock, dword dwIn)
{
	if(pDev->bInit == FALSE)
		return	FALSE;
	
	if(pDev->dwInNum == 0)
		return	FALSE;
	
	if(!RANGE_IN(dwBlock, 0, (pDev->dwInBlockNum-1)))
		return	FALSE;

devENTER(pDev);
	pDev->dwInVal[dwBlock] = dwIn;
devLEAVE(pDev);

	return	TRUE;
}

dword ioEmul_InputBitSet(CustIo_s *pDev, dword dwChan, boolean bOn)
{
	dword	blkID, blkChan;
	dword	dwMask;

	if(pDev->bInit == FALSE)
		return	FALSE;

	if(pDev->dwInNum == 0)
		return	FALSE;

	blkID = dwChan/32;
	blkChan = dwChan%32;

	if(!RANGE_IN(blkID, 0, (pDev->dwInBlockNum-1)))
		return	FALSE;

	if(!RANGE_IN(dwChan, 0, (pDev->dwInNum-1)))
		return	FALSE;

devENTER(pDev);
	if(bOn)
	{
		dwMask = (0x01 << blkChan);
		pDev->dwInVal[blkID] |= dwMask;
	}
	else
	{
		dwMask = (0x01 << blkChan);
		pDev->dwInVal[blkID] &= (~dwMask);
	}
devLEAVE(pDev);

	return TRUE;
}


/*--- END OF DioHal_ioEmul.C ---*/
